package overlay2

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"gitee.com/chuanjinge/go-container/pkg"
	"gitee.com/chuanjinge/go-container/pkg/dirfile"
)

/*
* 联合文件系统基本目录结构
*
[root@k8s-node-demo ufsdir]# tree
.
├── lower
│   ├── a
│   └── c
├── merged
│   ├── a
│   ├── b
│   └── c
├── upper
│   ├── a
│   └── b
└── work

	└── work
*/
type UfsDir struct {
	RootDir         string            // 联合文件系统根目录
	WorkDir         string            // 临时工作区，存储元数据等信息
	UpperDir        string            // 读写层
	LowerDir        string            // 只读层
	MergedDir       string            // 合并视图
	VolumeSharedMap map[string]string // 从宿主机上挂载到容器中的共享目录，key是宿主机，value是容器目录
}

const (
	DIR_WORK   = "work"
	DIR_LOWER  = "lower"
	DIR_UPPER  = "upper"
	DIR_MERGED = "merged"
)

// 获取容器理论路径
func GetContainerDir(containerId string) string {
	return fmt.Sprintf("/data/tinydocker/container/%s", containerId)
}

func GetContainerDirMerged(containerId string) string {
	return filepath.Join(GetContainerDir(containerId), DIR_MERGED)
}

func NewUfsDir(containerId string) *UfsDir {
	ufsDir := &UfsDir{}
	// 正常应该是读取配置文件，此处暂时写死
	rootDir := GetContainerDir(containerId)
	// 检查路径是否存在
	if _, err := os.Stat(rootDir); os.IsNotExist(err) {
		// 路径不存在，尝试创建
		log.Printf("Directory %s does not exist. Creating...\n", rootDir)
		if err := os.MkdirAll(rootDir, 0755); err != nil {
			log.Fatalf("Failed to create directory: %v", err)
		}
		log.Println("Directory created successfully.")
	} else if err != nil {
		log.Fatalf("Error checking directory: %v", err)
	} else {
		log.Println("Directory already exists.")
	}

	ufsDir.RootDir = rootDir
	// 可选：设置正确的权限和所有权
	setPermissionsAndOwnership(rootDir)

	// 继续创建 work/lower/upper/merged 用来进行操作
	dirList := []string{
		"work", "lower", "upper", "merged",
	}

	for _, dir := range dirList {
		dirFullPath := filepath.Join(rootDir, dir)
		if _, err := os.Stat(dirFullPath); os.IsNotExist(err) {
			if err := os.Mkdir(dirFullPath, 0755); err != nil {
				log.Fatal(err.Error())
				return nil
			}
		}
	}

	ufsDir.WorkDir = filepath.Join(rootDir, "work")
	ufsDir.LowerDir = filepath.Join(rootDir, "lower")
	ufsDir.UpperDir = filepath.Join(rootDir, "upper")
	ufsDir.MergedDir = filepath.Join(rootDir, "merged")
	ufsDir.VolumeSharedMap = make(map[string]string, 0)
	return ufsDir
}

func (ufs *UfsDir) ProcessSharedVolume(volumeList []string) error {
	ufs.ParseSharedVolume(volumeList)
	if err := ufs.initSharedVolume(); err != nil {
		return err
	}
	if err := ufs.mountSharedVolume(); err != nil {
		return err
	}
	return nil
}

// 初始化共享目录为可使用参数
func (ufs *UfsDir) ParseSharedVolume(volumeList []string) error {
	for _, volume := range volumeList {
		pathList := strings.Split(volume, ":")
		hostPath := pathList[0]
		containerPath := pathList[1]

		if hostPath == "" || containerPath == "" {
			continue
		}

		ufs.VolumeSharedMap[hostPath] = filepath.Join(ufs.MergedDir, containerPath)
	}

	return nil
}

// 共享目录的检查和创建
func (ufs *UfsDir) initSharedVolume() error {
	for hostPath, containerPathAtHost := range ufs.VolumeSharedMap {
		// hostPath不存在则创建为目录；
		// containerPath肯定不存在，得原样拷贝过来，是目录则创建目录，拷贝目录下所有文件，是文件的话，创建目录并拷贝该文件。
		fileInfo, err := os.Stat(hostPath)
		if err != nil && os.IsNotExist(err) {
			if err := os.MkdirAll(hostPath, 0755); err != nil {
				log.Printf("ERROR:initSharedVolume1:path:%s;error:%v", hostPath, err)
				return err
			} else {
				log.Printf("hostPath:%s 创建成功了", hostPath)
			}
		} else {
			log.Printf("hostPath:%s 已经存在了", hostPath)
		}

		if fileInfo.IsDir() {
			if err := os.MkdirAll(containerPathAtHost, 0755); err != nil {
				log.Printf("ERROR:initSharedVolume2:path:%s;error:%v", hostPath, err)
				return err
			}
			if err := pkg.CopyDir(hostPath, containerPathAtHost); err != nil {
				return err
			}
		} else {
			containerDirAtHost := filepath.Dir(containerPathAtHost)
			if err := os.MkdirAll(containerDirAtHost, 0755); err != nil {
				log.Printf("ERROR:initSharedVolume3:path:%s;error:%v", hostPath, err)
				return err
			}
			if err := pkg.CopyFile(hostPath, containerPathAtHost); err != nil {
				return err
			}
		}
	}
	return nil
}

func (ufs *UfsDir) mountSharedVolume() error {
	for hostPath, containerPathAtHost := range ufs.VolumeSharedMap {
		if err := syscall.Mount(hostPath, containerPathAtHost, "", syscall.MS_BIND, ""); err != nil {
			log.Printf("ERROR: mount错误：hostPath:%s;containerPath:%s;error:%v", hostPath, containerPathAtHost, err)
			return err
		}
	}

	return nil
}

func (ufs *UfsDir) UnmountSharedVolume() error {
	for _, containerPathAtHost := range ufs.VolumeSharedMap {
		if err := syscall.Unmount(containerPathAtHost, syscall.MNT_DETACH); err != nil {
			log.Printf("ERROR:unmount错误:containerPath:%s;error:%v", containerPathAtHost, err)
			return err
		}
	}
	return nil
}

// 将目标目录中基础镜像放入 lower 层
func (ufs *UfsDir) ReleaseBaseImageFromLocal(path string) error {
	if empty, err := dirfile.IsEmptyDir(path); err != nil || empty {
		return fmt.Errorf("镜像目录 %s 为空", path)
	}
	// 从path目录下拷贝过来，确保目标目录存在
	if err := os.MkdirAll(path, 0755); err != nil {
		log.Printf("Failed to create destination directory: %v\n", err)
		return err
	}
	// 拷贝源目录下的所有内容到目标目录
	if err := pkg.CopyDir(path, ufs.LowerDir); err != nil {
		log.Printf("Failed to copy directory: %v\n", err)
		return err
	}
	return nil
}

// 基于UfsDir转为overlay格式的联合目录格式
// 核心的命令：
// # mount 一个overlay的ufs文件系统
// # mount -t <文件系统类型> <设备名称> -o <目录名> 挂载点
// mount -t overlay overlay -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged
func (ufs *UfsDir) MountOverlayFs() error {
	source := "overlay"
	target := ufs.MergedDir
	fstype := "overlay"

	// 设置挂载选项
	data := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", ufs.LowerDir, ufs.UpperDir, ufs.WorkDir)

	// 执行挂载
	return syscall.Mount(source, target, fstype, 0, data)
}

// 把镜像工作区清空
func (ufs *UfsDir) Disapper() error {
	if err := ufs.unmountOverlayFs(); err != nil {
		return err
	}
	if err := ufs.deleteDirs(); err != nil {
		return err
	}
	return nil
}

// 卸载掉联合目录的挂载点
func (ufs *UfsDir) unmountOverlayFs() error {
	if err := syscall.Unmount(ufs.MergedDir, 0); err != nil {
		return fmt.Errorf("Failed to unmount: %v", err)
	}
	fmt.Println("Overlay filesystem unmounted successfully.")
	return nil
}

// 容器目录全都删掉
func (ufs *UfsDir) deleteDirs() error {
	if err := os.RemoveAll(ufs.MergedDir); err != nil {
		return fmt.Errorf("Remove merged dir %s error %v", ufs.MergedDir, err)
	}
	if err := os.RemoveAll(ufs.UpperDir); err != nil {
		return fmt.Errorf("Remove upper dir %s error %v", ufs.UpperDir, err)
	}
	if err := os.RemoveAll(ufs.WorkDir); err != nil {
		return fmt.Errorf("Remove work dir %s error %v", ufs.WorkDir, err)
	}
	if err := os.RemoveAll(ufs.LowerDir); err != nil {
		return fmt.Errorf("Remove work dir %s error %v", ufs.WorkDir, err)
	}

	return nil
}

// setPermissionsAndOwnership 设置指定目录的权限和所有权
func setPermissionsAndOwnership(dir string) {
	// 设置权限为 0755 (rwxr-xr-x)
	if err := os.Chmod(dir, 0755); err != nil {
		log.Printf("Failed to set permissions on %s: %v", dir, err)
	}
}
